package com.lry.pda.bottom.mysql.frontend;



import org.apache.commons.collections4.map.CaseInsensitiveMap;

import java.util.Map;
import java.util.Scanner;


public class Lexer {

	public int lookAhead = -1;
	Scanner s = new Scanner(System.in);

	public String yytext = "";
	public int yyleng = 0;

	private String input_buffer = "";
	private String current = "";

	public void clear(){
		lookAhead = -1;
		yytext = "";
		yyleng = 0;
		input_buffer = "";
		current = "";
	}
	private Map<String,Integer> keyWordMap = new CaseInsensitiveMap<>();

	public static void main(String[] args) {
		Lexer lexer = new Lexer();
		lexer.input();
		while(true){
			lexer.advance();
			if(lexer.match(MysqlTokenType.EOI.ordinal())){
				break;
			}
			System.out.print(lexer.yytext);
			System.out.println("\t\t"+MysqlTokenType.getSymbolStr(lexer.lookAhead));
		}
	}

	public Lexer(){
		initKeyWord();
	}

	private void initKeyWord() {
		keyWordMap.put("select",MysqlTokenType.SELECT_SYM.ordinal());
		keyWordMap.put("limit",MysqlTokenType.LIMIT_SYM.ordinal());
		keyWordMap.put("order",MysqlTokenType.ORDER_SYM.ordinal());
		keyWordMap.put("asc",MysqlTokenType.ASC_SYM.ordinal());
		keyWordMap.put("desc",MysqlTokenType.DESC_SYM.ordinal());
		keyWordMap.put("from",MysqlTokenType.FROM_SYM.ordinal());
		keyWordMap.put("where",MysqlTokenType.WHERE_SYM.ordinal());
		keyWordMap.put("and",MysqlTokenType.AND_SYM.ordinal());
		keyWordMap.put("group",MysqlTokenType.GROUP_SYM.ordinal());
		keyWordMap.put("by",MysqlTokenType.BY_SYM.ordinal());
	}

	private boolean isAllNum(char c) {
		if (Character.isAlphabetic(c) == true || Character.isDigit(c) == true) {
			return true;
		}
		return false;
	}


	public void input(){
		while (current == "") {
			while (true) {
				String line = s.nextLine();
				if (line.equals("end")) {
					break;
				}
				input_buffer += line;
			}

			if (input_buffer.length() == 0) {
				current = "";
			}
			current = input_buffer;
			current.trim();
		}
	}

	//select a, b, c from A where a >=    'ab \r \n\t  cd' order by  a,b,c asc limit 0,  1;
	private int lex() {
		if (current.isEmpty()) {
			return MysqlTokenType.EOI.ordinal();
		}
		boolean inStr = false;
		int strStart = 0,strEnd = 0;

		int i = 0;
		if(current.charAt(i)=='\''){
			for (; i < current.length(); i++) {
				if (current.charAt(i) == '\'') {
					if (!inStr) {
						strStart = i;
					} else {
						strEnd = i;
					}
					inStr = !inStr;
					if (!inStr) {
						yytext = current.substring(strStart+1, strEnd);
						current = current.substring(strEnd+1);
						if(isCompare()){
							return MysqlTokenType.WHERE_VAL.ordinal();
						}
						return MysqlTokenType.STR.ordinal();
					}
				}
			}
			if(i>=current.length()){
				yytext = current.substring(strStart+1);
				current = "";
				return MysqlTokenType.UNKNOWN_TOKEN.ordinal();
			}
		}

		i = 0;
		if(!inStr){
			yyleng = 0;
			yytext = current.substring(i, i + 1);
			switch (current.charAt(i)) {
				case ',':
					current = current.substring(1);
					return MysqlTokenType.COMMA.ordinal();
				case '=':
					current = current.substring(1);
					return MysqlTokenType.EQ.ordinal();
				case '>':
					if (current.charAt(i + 1) == '=') {
						yytext = current.substring(i, i + 2);
						current= current.substring(2);
						return MysqlTokenType.GE.ordinal();
					}
					current = current.substring(1);
					return MysqlTokenType.GT.ordinal();
				case '<':
					if (current.charAt(i + 1) == '=') {
						yytext = current.substring(i, i + 2);
						current= current.substring(2);
						return MysqlTokenType.LE.ordinal();
					}
					current = current.substring(1);
					return MysqlTokenType.LT.ordinal();
				case ';':
					current = current.substring(1);
					return MysqlTokenType.SEMI.ordinal();
				case '+':
					current = current.substring(1);
					return MysqlTokenType.PLUS.ordinal();
				case '*':
					current = current.substring(1);
					return MysqlTokenType.TIMES.ordinal();
				case '(':
					current = current.substring(1);
					return MysqlTokenType.LP.ordinal();
				case ')':
					current = current.substring(1);
					return MysqlTokenType.RP.ordinal();
				case ' ':
				case '\r':
				case '\t':
				case '\n':
					current = current.substring(1);
					return -1;
				default:
					if (!isAllNum(current.charAt(i))) {
						return MysqlTokenType.UNKNOWN_TOKEN.ordinal();
					} else {
						while (i < current.length() && isAllNum(current.charAt(i))) {
							i++;
							yyleng++;
						}
						yytext = current.substring(0, yyleng);
						current = current.substring(yyleng);
						return translateStringToToken();
					}
			}
		}
		return -1;
	}


	private boolean isCompare(){
		return match(MysqlTokenType.GE.ordinal())
				||match(MysqlTokenType.GT.ordinal())
				||match(MysqlTokenType.LE.ordinal())
				||match(MysqlTokenType.LT.ordinal())
				||match(MysqlTokenType.EQ.ordinal());
	}

	private int translateStringToToken() {
		int type = id_keyword_or_number();
		if (type != MysqlTokenType.UNKNOWN_TOKEN.ordinal()) {
			return type;
		}
		//field：字段名
		//table:表名
		if(match(MysqlTokenType.FROM_SYM.ordinal())){
			return MysqlTokenType.TABLE.ordinal();
		}
		return MysqlTokenType.FIELD.ordinal();
	}


	private int id_keyword_or_number() {
		int type = MysqlTokenType.UNKNOWN_TOKEN.ordinal();
		if (Character.isAlphabetic(yytext.charAt(0))) {
			type = isKeyWord(yytext);
		} else {
			if (isNum()) {
				if(isCompare()){
					type = MysqlTokenType.WHERE_VAL.ordinal();
				}else{
					type = MysqlTokenType.NUM_OR_ID.ordinal();
				}
			}
		}
		return type;
	}



	private boolean isNum() {
		int pos = 0;
		if (yytext.charAt(0) == '-' || yytext.charAt(0) == '+') {
			pos++;
		}

		for (; pos < yytext.length(); pos++) {
			if (Character.isDigit(yytext.charAt(pos)) != true) {
				break;
			}
		}

		return pos == yytext.length();
	}

	private int isKeyWord(String str) {
		if (keyWordMap.containsKey(str)) {
			return keyWordMap.get(str);
		}
		return MysqlTokenType.UNKNOWN_TOKEN.ordinal();
	}


	public boolean match(int token) {
		return token == lookAhead;
	}

	public void advance() {
		int lexVal = lex();
		while(lexVal==-1){
			lexVal = lex();
		}
		lookAhead = lexVal;
	}

}
